/******************************************************************************
 * Copyright (C) 671643387@qq.com
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *****************************************************************************/

#include "NodeCpp/Thread_WIN32.h"
#include <cassert>
#include "NodeCpp/Macros.h"
#include "NodeCpp/Runnable.h"

namespace NodeCpp
{
	ThreadImpl::ThreadImpl(void)
		: ID_(0)
		, Handle_(-1L)
		, Runnable_(NULL)
		, Priority_(PRIO_NORMAL_IMPL)
        , StartEvent_()
	{

	}

	ThreadImpl::~ThreadImpl(void)
	{
		if (Handle_ != -1L) {
			CloseHandle((HANDLE)Handle_);
		}
	}

	bool ThreadImpl::StartImpl(Runnable* _Runnable)
	{
		NODECPP_ASSERT(Handle_ == -1L);
		Runnable_ = _Runnable;
		Handle_ = _beginthreadex(NULL, 0, ThreadImpl::_Proc,
			this, 0, (unsigned int*)&ID_);
        if (Handle_ == -1L) {
            return false;
        }
        StartEvent_.Wait();
        return true;
	}

	void ThreadImpl::JoinImpl(void)
	{
		NODECPP_ASSERT(Handle_ != -1L);
		if (Handle_ != -1L) {
			WaitForSingleObject(HANDLE(Handle_), INFINITE);
		}
	}

	bool ThreadImpl::JoinableImpl(void)
	{
		return Handle_ != -1L;
	}

	bool ThreadImpl::SetPriorityImpl(int _Priority)
	{
		if (SetThreadPriority((HANDLE)Handle_, _Priority)) {
			Priority_ = Priority(_Priority);
			return true;
		}
		return false;
	}

	unsigned int ThreadImpl::_Proc(void* _Arg)
	{
		NODECPP_ASSERT(_Arg != NULL);
		ThreadImpl* _TH = static_cast<ThreadImpl*>(_Arg);
        _TH->StartEvent_.Set();
		_TH->Runnable_->Run();
		return 0;
	}

    ThreadImpl::ID ThisThreadImpl::GetIDImpl(void)
    {
        return GetCurrentThreadId();
    }

    void ThisThreadImpl::SleepImpl(long _Milliseconds)
    {
        Sleep((DWORD)_Milliseconds);
    }
}